{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 85
    },
    "colab_type": "code",
    "id": "n1Getoki4DUF",
    "outputId": "fc272523-0489-40ec-deb9-51ae07578b85"
   },
   "outputs": [],
   "source": [
    "# https://pypi.python.org/pypi/pydot\n",
    "# !pip install graphviz"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "2BVRzkJYvvww"
   },
   "outputs": [],
   "source": [
    "import copy\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import json\n",
    "\n",
    "\n",
    "import datetime as dt\n",
    "import random\n",
    "import time\n",
    "\n",
    "import math\n",
    "import bisect\n",
    "import itertools\n",
    "\n",
    "\n",
    "from IPython.display import clear_output\n",
    "\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimg\n",
    "from graphviz import Digraph\n",
    "from scipy.ndimage import shift\n",
    "#import pydot\n",
    "\n",
    "\n",
    "from getpass import getpass\n",
    "import os\n",
    "\n",
    "import TransferEntropy as te_utils\n",
    "import K2_utils as K2_utils\n",
    "import Utils as utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def apply_first_diff(df):\n",
    "    '''\n",
    "        Function that applies first difference in a DataFrame. \n",
    "        Returns the DataFrame of the first difference\n",
    "    '''\n",
    "    dist_diff = df.diff()\n",
    "    dist_diff.clip(lower=0, inplace=True)\n",
    "    dist_diff.dropna(inplace=True)\n",
    "    dist_diff.reset_index(drop=True, inplace=True)\n",
    "    dist_diff = dist_diff.astype(int)\n",
    "    \n",
    "    return dist_diff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "t9nN9piiG0aC"
   },
   "outputs": [],
   "source": [
    "def get_significante_TEs(df, thresh):\n",
    "    '''\n",
    "        Returns a DataFrame with the most significants Transfer entropies based on a threshold. \n",
    "                Not sginifcant ones are set as zero.\n",
    "        params:\n",
    "            df - DataFrame of computed TransferEntropies\n",
    "            thresh - Threshold of significance\n",
    "    '''\n",
    "    final_df = df.copy()\n",
    "    for row in df.columns:\n",
    "        for col in df.columns:\n",
    "            if df[row][col] < thresh:\n",
    "                final_df[row][col] = 0\n",
    "                \n",
    "    return final_df "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_te_by_h(k,l,h_window, a,b):\n",
    "    '''\n",
    "        transentropy a->b\n",
    "        te(k,l,h,a,b)\n",
    "        k - dimension of b\n",
    "        l - dimension of a\n",
    "        h -> time window in the future of a [0..h]\n",
    "    '''\n",
    "    #joint_p_ih_ik_jl = joint_probability_new(k,l,h,a,b, lbl_a, lbl_b)\n",
    "    \n",
    "    te_by_h = []\n",
    "    for h in np.arange(1,h_window):\n",
    "        joint_p_ih_ik_jl = te_utils.joint_probability(k,l,h,a,b)\n",
    "\n",
    "        joint_p_ih_ik = te_utils.joint_prob_ih_ik(k,l, joint_p_ih_ik_jl)\n",
    "        conditional_num = te_utils.conditional_prob(k,l,joint_p_ih_ik_jl)\n",
    "        conditional_den = te_utils.conditional_prob(k,0, joint_p_ih_ik)    \n",
    "        div = te_utils.conditional_div(k,l,conditional_num, conditional_den)\n",
    "\n",
    "        #log2 from the division of the conditionals -> #p(i_sub_t+h|i_sub_t**k, j_sub_t**l) /p(i_sub_t+h|i_t**k)\n",
    "        log2_div_cond = np.log2(div[div!=0])\n",
    "        te = np.sum(joint_p_ih_ik_jl[div!=0]*log2_div_cond)\n",
    "\n",
    "        te_by_h.append(te)\n",
    "        lag = np.argmax(te_by_h) + 1\n",
    "    return [max(te_by_h),lag]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "phi8XuryvvxI"
   },
   "outputs": [],
   "source": [
    "def compute_TE_and_lags_for_DataFrame(dist_df, h, k, l):\n",
    "    '''\n",
    "        Algorithm 1 - Generate graph of transferred entropies and relationship information delays\n",
    "        \n",
    "        Computation of transfer Entropy (TE) for a complete dataframe\n",
    "        Params:\n",
    "            dist_df : DataFrame of the variables to compute Transfer Entropy (TE)\n",
    "            h: Window of time horizon. The TE will be computed varying h from 0 to h, the 'h' who provides\n",
    "                maximum amount of entropy will be choosed by the method, and it will be set as highest transfer\n",
    "                entropy lag\n",
    "            l, k -  time horizons of TE\n",
    "    '''\n",
    "    start = time.process_time()\n",
    "    transEntropy = np.zeros([dist_df.columns.size,dist_df.columns.size])\n",
    "    lagEntropy = np.zeros([dist_df.columns.size,dist_df.columns.size])\n",
    "    sigValues =  np.zeros([dist_df.columns.size,dist_df.columns.size])\n",
    "    for i in np.arange(0, dist_df.columns.size):\n",
    "        for j in np.arange(0, dist_df.columns.size):\n",
    "            print('transfer entropy from ', dist_df.columns[i], ' to ', dist_df.columns[j])\n",
    "            if(j != i + dist_df.columns.size/2 and j!=i and j != i - dist_df.columns.size/2):\n",
    "                te_result = compute_te_by_h(k,l,h, dist_df[dist_df.columns[i]], dist_df[dist_df.columns[j]])\n",
    "                transEntropy[i][j] = te_result[0]\n",
    "                lagEntropy[i][j] = te_result[1]\n",
    "                \n",
    "            clear_output()\n",
    "    end = time.process_time()   \n",
    "    \n",
    "    print('Time for the complete computation: ', end - start, ' seconds.')\n",
    "    transEntropy_df = pd.DataFrame(transEntropy, columns = dist_df.columns, index = dist_df.columns)\n",
    "    lagEntropy_df = pd.DataFrame(lagEntropy, columns = dist_df.columns, index = dist_df.columns)\n",
    "    \n",
    "    return [transEntropy_df, lagEntropy_df]  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def remove_cycles(graph):\n",
    "    '''\n",
    "        Algorithm 2 - Removal of Graph Cycles\n",
    "        params:\n",
    "            graph: The graph to remove cycles - (np.Matrix)\n",
    "            \n",
    "    '''\n",
    "    graph_mat = copy.deepcopy(graph)\n",
    "    grafo_ac = np.zeros([len(graph_mat), len(graph_mat)], dtype=float)\n",
    "    ancestrals = [[] for el in np.arange(0, len(graph_mat))]\n",
    "    \n",
    "    max_val = max(graph_mat.flatten().tolist())\n",
    "    print(max_val)\n",
    "    idx_max = np.argmax(graph_mat.flatten().tolist())  \n",
    "\n",
    "    while(max_val > 0):\n",
    "        idx_row = int(np.floor(idx_max)/len(graph_mat))\n",
    "        idx_col = idx_max - len(graph_mat)*idx_row\n",
    "\n",
    "        impossible_nodes = []\n",
    "        if ancestrals[idx_row]:\n",
    "            impossible_nodes = get_node_genealogy(copy.deepcopy(ancestrals),idx_row, [])\n",
    "            if not idx_col in impossible_nodes:\n",
    "                grafo_ac[idx_row, idx_col] = graph_mat[idx_row, idx_col]\n",
    "                ancestrals[idx_col] += [idx_row] \n",
    "        else:\n",
    "            ancestrals[idx_col] += [idx_row]\n",
    "            grafo_ac[idx_row,idx_col] = max_val\n",
    "\n",
    "        graph_mat[idx_row, idx_col] = 0\n",
    "        max_val = max(graph_mat.flatten().tolist())\n",
    "        idx_max = np.argmax(graph_mat.flatten())\n",
    "        \n",
    "        \n",
    "    return grafo_ac"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_node_genealogy(genealogy, node, new_list):\n",
    "    '''\n",
    "        Algorithm 3 - Get node genealogy\n",
    "        Generate the genealogy of a node-\n",
    "        Params: \n",
    "            genealogy: The node genealogy - (Iniatially empty)\n",
    "            node: The node to compute genealogy \n",
    "            new_list: \n",
    "    '''\n",
    "    if np.all(np.unique(genealogy[node]) == ['x']):\n",
    "        return new_list\n",
    "    \n",
    "    if not node in new_list:\n",
    "        new_list.extend([node])\n",
    "            \n",
    "    if not genealogy[node]:\n",
    "        return new_list\n",
    "    else:\n",
    "        for i,no in enumerate(genealogy[node]):       \n",
    "            idx = no\n",
    "            node_to_list = [genealogy[node][i]]\n",
    "            genealogy[node][i] = 'x'\n",
    "            if no == 'x':\n",
    "                continue\n",
    "            if 'x' in genealogy[no]:\n",
    "                get_node_genealogy(genealogy, idx, new_list)   \n",
    "            elif not genealogy[no]:\n",
    "                new_list.extend(node_to_list)\n",
    "                genealogy[no] = ['x']\n",
    "                continue\n",
    "            else:\n",
    "                new_list.extend(node_to_list)\n",
    "                get_node_genealogy(genealogy, idx, new_list)             \n",
    "        else:\n",
    "            return get_node_genealogy(genealogy, node, new_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_common_and_virtual_parents(df,idx, summation, dict_lags, lista, dict_ways):\n",
    "    '''\n",
    "    \n",
    "        Algorithm 4 - Generation of Common and Virtual Parents.\n",
    "        \n",
    "            Given a node, computes the delays and the paths between it and its virtual and common parents\n",
    "            params:\n",
    "                df: The dataframe representing the graph, where weights are the lags,\n",
    "                summation: variable for lag summation\n",
    "                dict_lags: Empty dictionary for storing the lags from the \n",
    "                    paths between a node and its common/virtual parents.\n",
    "                lista: \n",
    "                dict_ways: Empty dictionary for storing the paths between a node and its common/virtual parents,\n",
    "    '''\n",
    "    lista.append(idx)\n",
    "    if np.all(df[idx] == np.zeros(len(df))):\n",
    "        return [dict_lags,dict_ways]\n",
    "    for i,dad_lag in enumerate(df[idx]):\n",
    "        if dad_lag > 0:\n",
    "          \n",
    "            summation += dad_lag\n",
    "            try:\n",
    "                dict_lags[df.columns[i]].append(summation)\n",
    "                dict_ways[df.columns[i]].append(lista)\n",
    "            except:\n",
    "                dict_lags[df.columns[i]] = [summation]\n",
    "                dict_ways[df.columns[i]]= [lista]\n",
    "        \n",
    "            gen_common_and_virtual_parents(df, df.columns[i], \n",
    "                                                       summation, dict_lags, \n",
    "                                                       lista[:], dict_ways)\n",
    "            summation -= dad_lag\n",
    "            \n",
    "    return [dict_lags, dict_ways] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ensemble_nodes_parents(nodes, df):\n",
    "    \n",
    "    '''\n",
    "        Algorithm 5 - Ensemble nodes parents.\n",
    "    \n",
    "        \n",
    "        This algorithm compute commons and vitual parents for all the nodes in the nodes list.\n",
    "            It returns a dictionary where for each key is a node and the value is\n",
    "            the path between each node and its parent (common or virtual) along the summation\n",
    "            of the lag from all the path.\n",
    "            \n",
    "        params:\n",
    "            nodes: The list of nodes to compute common and virtual parents\n",
    "            df: The dataframe representing the graph, where weights are the lags\n",
    "    '''\n",
    "    dic = {}\n",
    "    for node in nodes:\n",
    "        df_cp = df.copy()\n",
    "#         if not np.all(mat_cp[node] == np.zeros(len(mat_cp))):\n",
    "        dic[node] = gen_common_and_virtual_parents(df_cp, node, 0, {}, [],{})[0]\n",
    "    return dic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_k2_tree_from_lags(dici):\n",
    "    '''\n",
    "        Generate the K2 pre-order based on the dictionary of \n",
    "            lags/paths generated by ensemble_node_parents function\n",
    "        params:\n",
    "             dici: The dictionary with paths/lags from common and virtual parents\n",
    "    '''\n",
    "    tree_k2 = {}\n",
    "    for key_son, value in dici.items():    \n",
    "        if value:\n",
    "            for key_dad, value_dad in value.items():\n",
    "                for i, value in enumerate(value_dad):\n",
    "                    try:\n",
    "                        tree_k2[key_son].append(key_dad+\"-\"+str(i)+\"_\"+str(int(value)))\n",
    "                    except:\n",
    "                        tree_k2[key_son] = [key_dad+\"-\"+str(i)+\"_\"+str(int(value))]\n",
    "\n",
    "                    tree_k2[key_dad+\"-\"+str(i)+\"_\"+str(int(value))] = []\n",
    "        else:\n",
    "            tree_k2[key_son] = []\n",
    "    return tree_k2  \n",
    "        \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_dataset_of_K2_iteration(df, node, dict_lag):\n",
    "    '''\n",
    "        Algorithm 6: 'Generate_dataset_of_K2_iteration'\n",
    "        \n",
    "            This algorithm generate the dataset that will be used in each K2 iteration. \n",
    "            It genrates a shifted dataset according with lag of highest transfer of entropy\n",
    "            \n",
    "            params:\n",
    "                df: \n",
    "                node: Node to compute the dataframe shifted according to Lags\n",
    "                dict_lag: A dictionary with the lags between the node and its parents\n",
    "    '''\n",
    "    df_gen = df.copy()\n",
    "    if dict_lag[node]:\n",
    "        for key_dad, values_dad in dict_lag[node].items():\n",
    "            for i, val in enumerate(dict_lag[node][key_dad]): \n",
    "                df_gen[key_dad+\"-\"+str(i)+\"_\"+str(int(val))] = shift(df_gen[key_dad], int(val), order=0, mode='constant', cval=np.NaN)\n",
    "    df_gen.dropna(inplace=True)\n",
    "    return df_gen\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def k2_modified(df_cases, dict_lags,tree_ogn, c=1):\n",
    "    \n",
    "    '''\n",
    "        Algorithm 7 - K2-Modified\n",
    "        K2_modified algorithm implementation\n",
    "    \n",
    "        params:\n",
    "            df_cases: The dataframe of cases of the bayesian network, the columns are all the nodes \n",
    "            of the K2 pre-order \n",
    "            c: A factor for used in the evaluation of MDL score metric. Default = 1, (Optional)\n",
    "    \n",
    "        '''\n",
    "    tree = copy.deepcopy(tree_ogn)\n",
    "    dict_parents = {}\n",
    "    \n",
    "    dfs_list = []\n",
    "      \n",
    "    for col in df_cases.columns:\n",
    "        dfs_list.append(generate_dataset_of_K2_iteration(df_cases, col, dict_lags))\n",
    "    \n",
    "  \n",
    "    sigma = 0\n",
    "    parents = [[] for node in df_cases.columns]\n",
    "   \n",
    "    count = 0\n",
    "    for xi, col in enumerate(df_cases.columns):\n",
    "        \n",
    "        df = dfs_list[count]\n",
    "        df.dropna(inplace=True)\n",
    "        \n",
    "        count += 1\n",
    "        \n",
    "        pold = K2_utils.f_mdl(df_cases, xi, parents[xi], c)\n",
    "    \n",
    "        tree_xi = []\n",
    "        if tree:\n",
    "              tree_xi = tree[col]\n",
    "    \n",
    "        f_ances = []\n",
    "        while (True):\n",
    "            test_parents = [parents[xi]+[ances] for ances in tree_xi] if tree_xi else []            \n",
    "            f_ances = [K2_utils.f_mdl(df, xi,parent,c) for parent in test_parents] if test_parents else [K2_utils.f_mdl(df, xi, test_parents,c)]\n",
    "            \n",
    "            j_max = np.argmax(f_ances)\n",
    "\n",
    "            sigma = f_ances[j_max]> pold\n",
    "        \n",
    "            if sigma:\n",
    "                parents[xi] = parents[xi] + [no for no in [tree_xi[j_max]] if no not in parents[xi]]\n",
    "                pold = f_ances[j_max]\n",
    "  \n",
    "            if tree_xi:\n",
    "                del tree_xi[j_max]\n",
    "      \n",
    "            if(not sigma) or  (not tree_xi):\n",
    "                break\n",
    "        \n",
    "    for i,parent in enumerate(parents):\n",
    "        dict_parents[df_cases.columns[i]] = parent\n",
    "    return dict_parents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def reconstruction_of_the_graph(df_lags, k2_return):\n",
    "    '''\n",
    "        Algorithm 8 - Reconstruction of the graph\n",
    "        params:\n",
    "            df_lags - DataFrame with lags of the relationships\n",
    "                (Corresponds to the lags of graph with the most significant entropies and no cycles)\n",
    "            k2_return - Resulting tree delivered by K2-Modified (Dictionary)\n",
    "    \n",
    "    '''\n",
    "    df_clean = pd.DataFrame(data=np.zeros([len(df_lags.columns),len(df_lags.columns)], dtype=float), columns= df_lags.columns, index= df_lags.columns) \n",
    "\n",
    "    for key, values in k2_return.items():\n",
    "        node_son = key\n",
    "        lista_son = gen_common_and_virtual_parents(df_lags, node_son,0, {}, [], {})[1]\n",
    "\n",
    "        for node in values:\n",
    "            split_name = node.split('-')\n",
    "            node_ref = split_name[0]\n",
    "            lag = split_name[1].split('_')[1]\n",
    "            idx_ref = int(split_name[1].split('_')[0])\n",
    "\n",
    "            count = 0\n",
    "            path_list = lista_son[node_ref][idx_ref][::-1]\n",
    "\n",
    "            if len(lista_son[node_ref][idx_ref][::-1]) == 1:\n",
    "                df_clean.at[node_ref,node_son] = 1\n",
    "            while count < len(path_list) -1:\n",
    "                df_clean.at[path_list[count], path_list[count+1]] = 1\n",
    "                count +=1\n",
    "            if not len(lista_son[node_ref][idx_ref][::-1]) == 1:\n",
    "                df_clean.at[node_ref, path_list[0]] = 1\n",
    "                \n",
    "            df_clean = df_lags[df_clean>0].fillna(0)\n",
    "\n",
    "    return df_clean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "k2_mod_result = {}\n",
    "\n",
    "\n",
    "def apply_methodology(k,l,h, t, alarms_df):\n",
    "    '''\n",
    "        Application of all the stages of the proposed Method on the case study\n",
    "        params: \n",
    "            df_te - DataFrame with  transfer entropies of the relationships\n",
    "                (Corresponds to the graph with the most significant entropies and no cycles)\n",
    "            df_lags - DataFrame with lags of the relationships\n",
    "                (Corresponds to the lags of graph with the most significant entropies and no cycles)\n",
    "            alarms_df: DataFrame wih the industrial alarms that occurreddue to the disturbance application\n",
    "    '''\n",
    "    global k2_mod_result\n",
    "\n",
    "    try:\n",
    "        #\"Because it takes a long time to run TE, we had already provided the datasets with TE and lags \n",
    "        #computed on the 'data', you can\"\n",
    "        with open(\"data/df_te.csv\") as df_te, open(\"data/df_lags.csv\") as df_lags:\n",
    "            df_te = pd.read_csv(df_te, index_col=0)\n",
    "            df_lags = pd.read_csv(df_lags, index_col=0)\n",
    "    except:\n",
    "        print(\"Files do not exist, computing Transfer Entropy for dataframe\")\n",
    "        df_te_and_lags = compute_TE_and_lags_for_DataFrame(alarms_df, h, k , l)\n",
    "        df_te = df_te_and_lags[0]\n",
    "        df_lags = df_te_and_lags[1]\n",
    "        \n",
    "    \n",
    "    #Threshold proposed by the article -     t = 0.007668474476869511\n",
    "    \n",
    "    #Apply threshold on DataFrame (graph) of tranfer entropies\n",
    "    te_significants = get_significante_TEs(df_te, t)\n",
    "    \n",
    "    \n",
    "    #Removal of Cycles of graph of TransferEntropies\n",
    "    te_no_cycle = pd.DataFrame(data = remove_cycles(te_significants.values), \n",
    "                                   columns=te_significants.columns, index=te_significants.columns)\n",
    "\n",
    "    # Utilizing the graph containing the lags of the relationships\n",
    "    te_lags_no_cycle = df_lags[te_no_cycle > 0].fillna(0)\n",
    "\n",
    "    #Computing Common and Virtual Parents lags DataFrame\n",
    "    dict_lags = ensemble_nodes_parents(te_lags_no_cycle.columns, te_lags_no_cycle)\n",
    "\n",
    "    #Generation of K2 pre-order\n",
    "    k2_tree = gen_k2_tree_from_lags(dict_lags)\n",
    "\n",
    "    #Computation of Modified K2\n",
    "    k2_mod_result = k2_modified(alarms_df,dict_lags, k2_tree,1)\n",
    "\n",
    "    #Reconstruction of the final graph\n",
    "    final_graph = reconstruction_of_the_graph(te_lags_no_cycle, k2_mod_result)\n",
    "    return final_graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time for the complete computation:  11251.001657335  seconds.\n",
      "0.1512784756129776\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-8-ebe0155e337d>:10: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison\n",
      "  if np.all(np.unique(genealogy[node]) == ['x']):\n"
     ]
    }
   ],
   "source": [
    "\n",
    "#We have pre process this data applying a mooving mean of 5 samples, this is not an obligated stage, but you\n",
    "#can do it by using the function apply_mooving_mean(df, mean) from utils.py script:\n",
    "\n",
    "alarms = pd.read_csv(\"data/alarms_m5.csv\", index_col=0)\n",
    "\n",
    "#Parameters used in the case study of the article\n",
    "k = 1\n",
    "l = 1\n",
    "h = 50\n",
    "t = 0.007668474476869511\n",
    "\n",
    "final_graph = apply_methodology(k, l, h, t, alarms)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>x01_high</th>\n",
       "      <th>x02_high</th>\n",
       "      <th>x03_high</th>\n",
       "      <th>x06_high</th>\n",
       "      <th>x07_high</th>\n",
       "      <th>x08_high</th>\n",
       "      <th>x09_high</th>\n",
       "      <th>x21_high</th>\n",
       "      <th>x01_low</th>\n",
       "      <th>x02_low</th>\n",
       "      <th>x03_low</th>\n",
       "      <th>x06_low</th>\n",
       "      <th>x07_low</th>\n",
       "      <th>x08_low</th>\n",
       "      <th>x09_low</th>\n",
       "      <th>x21_low</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>x01_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x02_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x03_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x06_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x07_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x08_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x09_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>42.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>8.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x21_high</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>31.0</td>\n",
       "      <td>29.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x01_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>49.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x02_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x03_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x06_low</th>\n",
       "      <td>49.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>48.0</td>\n",
       "      <td>40.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x07_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x08_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x09_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x21_low</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          x01_high  x02_high  x03_high  x06_high  x07_high  x08_high  \\\n",
       "x01_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x02_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x03_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x06_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x07_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x08_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x09_high       0.0       0.0       0.0       0.0      42.0       0.0   \n",
       "x21_high       0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x01_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x02_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x03_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x06_low       49.0       0.0       0.0       0.0       0.0      48.0   \n",
       "x07_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x08_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x09_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "x21_low        0.0       0.0       0.0       0.0       0.0       0.0   \n",
       "\n",
       "          x09_high  x21_high  x01_low  x02_low  x03_low  x06_low  x07_low  \\\n",
       "x01_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x02_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x03_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x06_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x07_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x08_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x09_high       0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x21_high       0.0       0.0      0.0      0.0      0.0     31.0     29.0   \n",
       "x01_low        0.0      49.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x02_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x03_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x06_low       40.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x07_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x08_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x09_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "x21_low        0.0       0.0      0.0      0.0      0.0      0.0      0.0   \n",
       "\n",
       "          x08_low  x09_low  x21_low  \n",
       "x01_high      0.0      0.0      0.0  \n",
       "x02_high      0.0      0.0      0.0  \n",
       "x03_high      0.0      0.0      0.0  \n",
       "x06_high      0.0      0.0      0.0  \n",
       "x07_high      0.0      0.0      0.0  \n",
       "x08_high      0.0      0.0      0.0  \n",
       "x09_high      0.0      0.0      8.0  \n",
       "x21_high      0.0      0.0      0.0  \n",
       "x01_low       0.0      0.0      0.0  \n",
       "x02_low       0.0      0.0      0.0  \n",
       "x03_low       0.0      0.0      0.0  \n",
       "x06_low       0.0      0.0      0.0  \n",
       "x07_low       0.0      0.0      0.0  \n",
       "x08_low       0.0      0.0      0.0  \n",
       "x09_low       0.0      0.0      0.0  \n",
       "x21_low       0.0      0.0      0.0  "
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "final_graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Saving the final graph\n",
    "final_graph.to_csv('final_graph_latest.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Final Graph\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: %3 Pages: 1 -->\n",
       "<svg width=\"310pt\" height=\"392pt\"\n",
       " viewBox=\"0.00 0.00 310.17 392.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 388)\">\n",
       "<title>%3</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-388 306.17,-388 306.17,4 -4,4\"/>\n",
       "<!-- x09_high -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>x09_high</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"81.09\" cy=\"-105\" rx=\"37.17\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"81.09\" y=\"-102.5\" font-family=\"Times,serif\" font-size=\"10.00\">x09_high</text>\n",
       "</g>\n",
       "<!-- x07_high -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>x07_high</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"37.09\" cy=\"-18\" rx=\"37.17\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"37.09\" y=\"-15.5\" font-family=\"Times,serif\" font-size=\"10.00\">x07_high</text>\n",
       "</g>\n",
       "<!-- x09_high&#45;&gt;x07_high -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>x09_high&#45;&gt;x07_high</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M72.39,-87.21C66.13,-75.1 57.55,-58.53 50.42,-44.76\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"53.47,-43.03 45.76,-35.76 47.25,-46.25 53.47,-43.03\"/>\n",
       "<text text-anchor=\"middle\" x=\"78.09\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">42.0</text>\n",
       "</g>\n",
       "<!-- x21_low -->\n",
       "<g id=\"node9\" class=\"node\">\n",
       "<title>x21_low</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"126.09\" cy=\"-18\" rx=\"33.61\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"126.09\" y=\"-15.5\" font-family=\"Times,serif\" font-size=\"10.00\">x21_low</text>\n",
       "</g>\n",
       "<!-- x09_high&#45;&gt;x21_low -->\n",
       "<g id=\"edge8\" class=\"edge\">\n",
       "<title>x09_high&#45;&gt;x21_low</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M89.98,-87.21C96.43,-75.02 105.27,-58.32 112.59,-44.49\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"115.78,-45.94 117.37,-35.47 109.59,-42.67 115.78,-45.94\"/>\n",
       "<text text-anchor=\"middle\" x=\"118.59\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">8.0</text>\n",
       "</g>\n",
       "<!-- x21_high -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>x21_high</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"215.09\" cy=\"-279\" rx=\"37.17\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"215.09\" y=\"-276.5\" font-family=\"Times,serif\" font-size=\"10.00\">x21_high</text>\n",
       "</g>\n",
       "<!-- x06_low -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>x06_low</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"173.09\" cy=\"-192\" rx=\"33.61\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"173.09\" y=\"-189.5\" font-family=\"Times,serif\" font-size=\"10.00\">x06_low</text>\n",
       "</g>\n",
       "<!-- x21_high&#45;&gt;x06_low -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>x21_high&#45;&gt;x06_low</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M206.79,-261.21C200.77,-249.02 192.51,-232.32 185.68,-218.49\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"188.79,-216.88 181.22,-209.47 182.52,-219.98 188.79,-216.88\"/>\n",
       "<text text-anchor=\"middle\" x=\"213.09\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">31.0</text>\n",
       "</g>\n",
       "<!-- x07_low -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>x07_low</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"258.09\" cy=\"-192\" rx=\"33.61\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"258.09\" y=\"-189.5\" font-family=\"Times,serif\" font-size=\"10.00\">x07_low</text>\n",
       "</g>\n",
       "<!-- x21_high&#45;&gt;x07_low -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>x21_high&#45;&gt;x07_low</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M223.73,-261.29C226.71,-255.5 230.06,-248.97 233.09,-243 237.08,-235.12 241.39,-226.53 245.29,-218.72\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"248.47,-220.2 249.8,-209.69 242.2,-217.08 248.47,-220.2\"/>\n",
       "<text text-anchor=\"middle\" x=\"256.09\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">29.0</text>\n",
       "</g>\n",
       "<!-- x01_low -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>x01_low</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"215.09\" cy=\"-366\" rx=\"33.61\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"215.09\" y=\"-363.5\" font-family=\"Times,serif\" font-size=\"10.00\">x01_low</text>\n",
       "</g>\n",
       "<!-- x01_low&#45;&gt;x21_high -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>x01_low&#45;&gt;x21_high</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M215.09,-347.8C215.09,-336.16 215.09,-320.55 215.09,-307.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"218.59,-307.18 215.09,-297.18 211.59,-307.18 218.59,-307.18\"/>\n",
       "<text text-anchor=\"middle\" x=\"231.09\" y=\"-318.8\" font-family=\"Times,serif\" font-size=\"14.00\">49.0</text>\n",
       "</g>\n",
       "<!-- x06_low&#45;&gt;x09_high -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>x06_low&#45;&gt;x09_high</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M156.64,-175.8C142.34,-162.59 121.42,-143.27 105.23,-128.3\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"107.42,-125.57 97.7,-121.35 102.67,-130.71 107.42,-125.57\"/>\n",
       "<text text-anchor=\"middle\" x=\"149.09\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">40.0</text>\n",
       "</g>\n",
       "<!-- x01_high -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>x01_high</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"173.09\" cy=\"-105\" rx=\"37.17\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"173.09\" y=\"-102.5\" font-family=\"Times,serif\" font-size=\"10.00\">x01_high</text>\n",
       "</g>\n",
       "<!-- x06_low&#45;&gt;x01_high -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>x06_low&#45;&gt;x01_high</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M173.09,-173.8C173.09,-162.16 173.09,-146.55 173.09,-133.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"176.59,-133.18 173.09,-123.18 169.59,-133.18 176.59,-133.18\"/>\n",
       "<text text-anchor=\"middle\" x=\"189.09\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">49.0</text>\n",
       "</g>\n",
       "<!-- x08_high -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>x08_high</title>\n",
       "<ellipse fill=\"#c9c9c9\" stroke=\"gray\" cx=\"265.09\" cy=\"-105\" rx=\"37.17\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"265.09\" y=\"-102.5\" font-family=\"Times,serif\" font-size=\"10.00\">x08_high</text>\n",
       "</g>\n",
       "<!-- x06_low&#45;&gt;x08_high -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>x06_low&#45;&gt;x08_high</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M189.53,-175.8C203.84,-162.59 224.75,-143.27 240.95,-128.3\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"243.5,-130.71 248.47,-121.35 238.75,-125.57 243.5,-130.71\"/>\n",
       "<text text-anchor=\"middle\" x=\"241.09\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">48.0</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.dot.Digraph at 0x7f612c646910>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Plot of graph of causal realationships\n",
    "print('Final Graph')\n",
    "utils.graph_simple(final_graph)"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "TransEntropy.ipynb",
   "provenance": [],
   "toc_visible": true,
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
